/// Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Microsoft.VSPowerToys.PackInstallerDataModel;
using System.Diagnostics;

namespace Microsoft.VSPowerToys.PackInstaller
{
	/// <summary>
	/// This control houses all the data about a tool to display to the user
	/// </summary>
	public partial class ToolSummaryControl : UserControl
	{
		private const int borderSize = 7;
		private const int glyphSize = 16;

		ToolItem toolData;

        private string toolName;

		private bool maintenanceModeEnabled;

        /// <summary>
        /// Property for whether we're installing or uninstalling
        /// </summary>
		public bool MaintenanceModeEnabled
		{
            get { return this.maintenanceModeEnabled = false; }
            set { this.maintenanceModeEnabled = value; }
		}

        /// <summary>
        /// This enum represents whether the description is expanded or collapsed.
        /// </summary>
        public enum SummaryDescriptionState
        {
            Collapsed,
            Expanded
        }

        private SummaryDescriptionState descriptionState = SummaryDescriptionState.Collapsed;

        /// <summary>
        /// Property for the current state of the description
        /// </summary>
        public SummaryDescriptionState DescriptionState
        {
            get { return this.descriptionState; }
            set { this.descriptionState = value; }
        }


        /// <summary>
        /// Gets the ToolItem object linked to this control
        /// </summary>
        public ToolItem ToolData
        {
            get { return this.toolData; }
        }

		/// <summary>
		/// The name of the tool
		/// </summary>
		public string ToolName
		{
			get { return this.toolName; }
			set 
			{ 
				this.toolName = value;
				// We want to append the name and version together on a single label.
                this.toolNameLinkLabel.Text = this.toolName + " " + this.toolVersion;
			}
		}

		/// <summary>
		/// The description of the tool
		/// </summary>
		public string Description
		{
            get { return this.toolDescriptionLabel.Text; }
            set { this.toolDescriptionLabel.Text = value; }
		}

		private string toolVersion;

		/// <summary>
		/// The current version of the tool
		/// </summary>
		public string Version
		{
			get { return this.toolVersion; }
			set 
			{
				this.toolVersion = value;
				// We want to append the name and version together on a single label.
                this.toolNameLinkLabel.Text = this.toolName + " " + this.toolVersion;
			}
		}

		/// <summary>
		/// Accessor to get the check box value out of the control
		/// </summary>
		public bool InstallToolFlag
		{
            get { return this.installToolCheckBox.Checked; }
			set 
			{
				if (!this.maintenanceModeEnabled)
				{
					if (value && !this.toolData.CurrentlyInstalled)
					{
                        this.installToolCheckBox.Checked = value;
					}
					else if (!value)
					{
                        this.installToolCheckBox.Checked = value;
					}
				}
				else
				{
					if (value && this.toolData.CurrentlyInstalled)
					{
                        this.installToolCheckBox.Checked = value;
					}
					else if (!value)
					{
                        this.installToolCheckBox.Checked = value;
					}
				}
			}
		}

        /// <summary>
        /// Returns true if user can select the tool for current mode of operation.
        /// </summary>
        public bool Active
        {
            get { return this.installToolCheckBox.Enabled; }
        }

		/// <summary>
		/// Constructor
		/// </summary>
		public ToolSummaryControl()
		{
			InitializeComponent();
		}

		/// <summary>
		/// This method checks the state of each glyph variable and adds the glyph if necessary.
		/// The glyphs are dynamically allocated and flow right to left.
		/// </summary>
		/// <param name="toolData"
		private void SetupGlyphs()
		{
			// Setup the glyph to indicate whether this tool is already installed.
			// This glyph only appears if the tool is installed, there is no "not installed" glyph.
            if (this.toolData.CurrentlyInstalled)
			{
				PictureBox installedBox = new PictureBox();
				installedBox.SizeMode = PictureBoxSizeMode.AutoSize;
                installedBox.Name = "installedBox";
				installedBox.Anchor = AnchorStyles.Right | AnchorStyles.Top;
				installedBox.Image = Microsoft.VSPowerToys.PackInstaller.Properties.Resources.TinyOK;
                this._ToolTipProvider.SetToolTip(installedBox, PackInstaller.Strings.ToolCurrentlyInstalledTooltip);
		        this.glyphLayout.Controls.Add(installedBox);
			}
        }

		/// <summary>
		/// This method loads data from the ToolDataItem object into the UI elements.
		/// </summary>
		/// <param name="newToolData"></param>
		public void LoadToolData(ToolItem newToolData)
		{
			if (newToolData != null)
			{
				this.toolData = newToolData;
                this.ToolName = newToolData.ToolName;
                this.Description = newToolData.DetailedDescription;
                this.Version = newToolData.VersionString;

				// Setup a tooltip so that when the name link gets hovered over there are some instructions.
                this._ToolTipProvider.SetToolTip(toolNameLinkLabel, toolData.HomepageUrl.ToString());

				RefreshInstallToolCheckBox();

				SetupGlyphs();

                RefreshDescriptionSizes();
                CollapseSummary();
			}
			return;
		}

		/// <summary>
		/// This method enables the check box for installing the tool based on the maintenance mode setting.
		/// </summary>
		public void RefreshInstallToolCheckBox()
		{
			if (!this.maintenanceModeEnabled)
			{
				this.installToolCheckBox.Enabled = !this.toolData.CurrentlyInstalled;
                this.Visible = true;
                this.Enabled = true;
			}
			else
			{
                this.Enabled = this.toolData.CurrentlyInstalled;
				this.installToolCheckBox.Enabled = this.toolData.CurrentlyInstalled;
                this.Visible = this.installToolCheckBox.Enabled;
			}
		}

		/// <summary>
		/// Event for when the state of the check box changes.  We handle this bit separately from the click
		/// to avoid some problems with the hosting control setting the check boxes and then re-raising events.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void _InstallToolCheckBox_CheckedChanged(object sender, EventArgs e)
		{
			// Set the install flag for the version we want
			this.toolData.InstallTool = installToolCheckBox.Checked;
		}

		/// <summary>
		/// The event raised by clicking on the name link.  This will bring up the system registered browser to the home page URL.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void _ToolNameLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			System.Diagnostics.Process.Start(this.toolData.HomepageUrl.ToString());
		}

		/// <summary>
		/// Click event for the check box.  We use this event to tell the hosting control that we 
		/// need to update the state of the overall pack's check box.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void _InstallToolCheckBox_Click(object sender, EventArgs e)
		{
			PackListControl parentControl = this.Parent.Parent as PackListControl;
			if (parentControl != null)
			{
				parentControl.UpdatePartialSelectState();
			}
		}

		/// <summary>
		/// Method to shrink the summary control down to a single "row"
		/// </summary>
		public void CollapseSummary()
		{
            this.toolDescriptionLabel.Height = this.toolDescriptionLabel.Font.Height * 2;
            this.moreLessLinkLabel.Text = Strings.MoreButtonText;
            this.DescriptionState = SummaryDescriptionState.Collapsed;
		}

		/// <summary>
		/// Method to expand the summary control up to show the details of a tool
		/// </summary>
		public void ExpandSummary()
		{
            TextFormatFlags whichFlags = (TextFormatFlags.WordBreak | TextFormatFlags.WordEllipsis);
            Size textSize = TextRenderer.MeasureText(this.toolData.DetailedDescription, this.toolDescriptionLabel.Font, this.toolDescriptionLabel.ClientSize, whichFlags);
            this.toolDescriptionLabel.Height = textSize.Height;
            this.moreLessLinkLabel.Text = Strings.LessButtonText;
            this.DescriptionState = SummaryDescriptionState.Expanded;
        }

        /// <summary>
        /// This method resizes the description box based on how much text needs to be displayed.
        /// This acts as a vertical auto resize of the content.  The collapsed size is enough for two lines of text.
        /// </summary>
        public void RefreshDescriptionSizes()
        {
            if (this.toolData != null)
            {
                TextFormatFlags whichFlags = TextFormatFlags.WordBreak | TextFormatFlags.EndEllipsis;
                Size textSize = TextRenderer.MeasureText(this.toolData.DetailedDescription, this.toolDescriptionLabel.Font, this.toolDescriptionLabel.ClientSize, whichFlags);

                if (textSize.Height > this.toolDescriptionLabel.Font.Height * 2)
                {
                    this.moreLessLinkLabel.Visible = true;
                }
                else
                {
                    this.moreLessLinkLabel.Visible = false;
                }
            }
        }


        /// <summary>
        /// Event for when the user clicks on the expand / collapse button
        /// We figure out if we're already collapsed and then call the appropriate
        /// method to switch states.  We also need to notify the pack container to 
        /// resize itself based on our new size.
        /// </summary>
        private void moreLessLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (this.descriptionState == SummaryDescriptionState.Collapsed)
            {
                ExpandSummary();
            }
            else
            {
                CollapseSummary();
            }

            this.Refresh();
        }


        /// <summary>
        /// This method refreshes the sizes of the description, and forces the control to
        /// "re" expand or collapse the description.
        /// </summary>
        public void SizeToContent()
        {
            RefreshDescriptionSizes();
            if (this.descriptionState == SummaryDescriptionState.Expanded)
            {
                ExpandSummary();
            }
            else
            {
                CollapseSummary();
            }
            this.Refresh();
        }


        private void ToolSummaryControl_SizeChanged(object sender, EventArgs e)
        {
            RefreshDescriptionSizes();
        }
	}
}
